#include "sal.h"
#include "ctc_warmboot.h"
#include "ctc_opf.h"
#include "ctc_pmem.h"

#include "ctc_const.h"
#include "ctc_register.h"

extern uint8 g_ctcs_api_en;
ctc_wb_master_t *g_wb_master[CTC_MAX_LOCAL_CHIP_NUM_PP];


#define CTC_WB_APPID_HASH_NUM 512
#define CTC_WB_APPID_HASH_BlOCK_NUM 16


#define CTC_WB_APPID_NUM 180
#define CTC_WB_APPID_SUB_ID_NUM 32



extern
int32 ctcs_global_ctl_get(uint8 lchip, ctc_global_control_type_t type, void* value);
extern
int32 ctc_global_ctl_get(ctc_global_control_type_t type, void* value);
extern
int32 ctcs_global_ctl_set(uint8 lchip, ctc_global_control_type_t type, void* value);
extern
int32 ctc_global_ctl_set(ctc_global_control_type_t type, void* value);


STATIC int32
ctc_wb_restore(uint8 lchip);

const char *_ctc_wb_feature_desc(int32 feature)
{
    switch(feature)
    {
     case CTC_FEATURE_PORT:
        return "Port";
     case CTC_FEATURE_VLAN:
        return "Vlan";
     case CTC_FEATURE_LINKAGG:
        return "Linkagg";
     case CTC_FEATURE_CHIP:
         return "Chip";
     case CTC_FEATURE_FTM:
         return "FTM";
     case CTC_FEATURE_NEXTHOP:
        return "Nexthop";
     case CTC_FEATURE_L2:
        return "L2";
     case CTC_FEATURE_L3IF:
        return "L3IF";
     case CTC_FEATURE_IPUC:
        return "IPUC";
     case CTC_FEATURE_IPMC:
        return "IPMC";
     case CTC_FEATURE_IP_TUNNEL:
        return "IP_Tunnel";
     case CTC_FEATURE_SCL:
        return "SCL";
     case CTC_FEATURE_ACL:
        return "ACL";
     case CTC_FEATURE_QOS:
        return "Qos";
     case CTC_FEATURE_SECURITY:
        return "Security";
     case CTC_FEATURE_STATS:
        return "Stats";
     case CTC_FEATURE_MPLS:
        return "Mpls";
     case CTC_FEATURE_OAM:
         return "OAM";
     case CTC_FEATURE_APS:
         return "APS";
     case CTC_FEATURE_PTP:
         return "PTP";
     case CTC_FEATURE_DMA:
         return "DMA";
     case CTC_FEATURE_INTERRUPT:
         return "Interrupt";
     case CTC_FEATURE_PACKET:
        return "Packet";
     case CTC_FEATURE_PDU:
        return "PDU";
     case CTC_FEATURE_MIRROR:
         return "Mirror";
     case CTC_FEATURE_BPE:
         return "BPE";
     case CTC_FEATURE_STACKING:
         return "Stacking";
     case CTC_FEATURE_OVERLAY:
         return "Overlay";
     case CTC_FEATURE_IPFIX:
         return "IPFIX";
     case CTC_FEATURE_EFD:
         return "EFD";
     case CTC_FEATURE_MONITOR:
        return "Monitor";
     case CTC_FEATURE_FCOE:
        return "FCOE";
     case CTC_FEATURE_TRILL:
        return "TRILL";
     case CTC_FEATURE_WLAN:
        return "WLAN";
     case CTC_FEATURE_NPM:
        return "NPM";
     case CTC_FEATURE_VLAN_MAPPING:
        return "VLAN_Mapping";
     case CTC_FEATURE_DOT1AE:
        return "Dot1AE";
     case CTC_FEATURE_SRV6:
         return "SRv6";
     case CTC_FEATURE_DTEL:
         return "DTEL";
     case CTC_FEATURE_DIAG:
        return "Diag";
     case CTC_FEATURE_SC_OAM:
        return "Sc_OAM";
     case CTC_FEATURE_SYNC_ETHER:
        return "SyncE";
     case CTC_FEATURE_APP_VLAN_PORT:
        return "XGPON";
     case CTC_FEATURE_DATAPATH:
         return "Datapath";
     case CTC_FEATURE_REGISTER:
         return "Register";
     case CTC_FEATURE_FLEXE:
          return "FlexE";
    case CTC_FEATURE_PON:
       return "PON";
    case CTC_FEATURE_XDATA:
       return "XDATA";
          default:
            return "Unknown";
      }

}
uint32
ctc_wb_dm_hash_make(ctc_wb_appid_t* node)
{
    return ctc_hash_caculate(sizeof(node->app_id), &(node->app_id));
}

bool
ctc_wb_dm_hash_cmp(ctc_wb_appid_t* stored_node, ctc_wb_appid_t* lkup_node)
{
    if (!stored_node || !lkup_node)
    {
        return FALSE;
    }

    if (stored_node->app_id== lkup_node->app_id)
    {
        return TRUE;
    }

    return FALSE;
}

uint32 ctc_wb_get_sync_bmp(uint8 lchip, uint8 mod_id)
{
   if (!CTC_WB_DM_MODE(lchip))
   {
       return 0;
   }

   return (mod_id < CTC_FEATURE_MAX)? g_wb_master[lchip]->sync_bmp[mod_id] : 0;
}

uint8 _ctc_wb_bmp_clear(uint8 lchip)
{
    uint8 loop = 0;
    if(!CTC_WB_DM_MODE(lchip) )
    {
        return TRUE;
    }

    for(;loop < CTC_FEATURE_MAX;loop++)
    {
        if(g_wb_master[lchip]->sync_bmp[loop] && (loop != CTC_FEATURE_STATS))
        {
           CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "The HW DB ad SW DB are inconsistent before last reboot(lchip:%d module[%d] syncbmp[0x%x]).\n",lchip, loop, g_wb_master[lchip]->sync_bmp[loop]);
            return FALSE;
        }
    }
    return TRUE;
}

void ctc_wb_set_sync_bmp(uint8 lchip, uint8 mod_id, uint8 sub_id,uint8 enable)
{
       if(!CTC_IS_BIT_SET( g_wb_master[lchip]->appid_en[mod_id],sub_id))
        {
           return ;
        }
        if(enable)
        {
            CTC_BIT_SET(g_wb_master[lchip]->sync_bmp[mod_id], sub_id);
        }
        else
        {
            CTC_BIT_UNSET(g_wb_master[lchip]->sync_bmp[mod_id], sub_id);
        }

    return ;
}


int32 _ctc_wb_sync_bmp_init(uint8 lchip)
{
    uint8 loop = 0;
    if (!CTC_WB_DM_MODE(lchip))
    {
       return CTC_E_NOT_SUPPORT;
    }

    for(;loop < CTC_FEATURE_MAX;loop++)
    {
        g_wb_master[lchip]->sync_bmp[loop] = 0;
    }
    return CTC_E_NONE;
}


int32 ctc_wb_init(uint8 lchip, ctc_wb_api_t *wb_api)
{
    int32 ret = CTC_E_NONE;
    uint8 status = 0;
    uint8 pp_id = lchip - CTC_MAP_LCHIP_BASE(lchip);
	uint8 pp_num = CTC_MAP_LDEV_PP_NUM(CTC_MAP_LDEV(lchip));

#ifndef WARMBOOT
    if(wb_api && wb_api->enable)
    {
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "warmboot is not support!\n");
    }
    return CTC_E_NONE;
#endif

    if (!wb_api || !wb_api->enable ||
     (!wb_api->mode && (!wb_api->init || !wb_api->init_done || !wb_api->sync || !wb_api->add_entry || !wb_api->sync_done || !wb_api->query_entry) ) )
    {
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "warmboot is not support!\n");
        return CTC_E_NONE;
    }
    if(wb_api->mode && (!wb_api->start_addr || !wb_api->size))
    {
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "warmboot memeory size is invalid:%u \n",wb_api->size);
        return CTC_E_NONE;
    }

    if (!g_wb_master[lchip])
    {
        g_wb_master[lchip] = mem_malloc(MEM_SYSTEM_MODULE,sizeof(ctc_wb_master_t));
        if (!g_wb_master[lchip])
        {
            return CTC_E_NO_MEMORY;
        }
        sal_memset(g_wb_master[lchip], 0, sizeof(ctc_wb_master_t));
    }
    else
    {
        return CTC_E_NONE;
    }

    if(wb_api->mode)
    {
        g_wb_master[lchip]->start_addr = wb_api->start_addr;
        g_wb_master[lchip]->total_size  = wb_api->size;
        g_wb_master[lchip]->sync_bmp = (uint32 *)g_wb_master[lchip]->start_addr +  CTC_FEATURE_MAX*pp_id;
        g_wb_master[lchip]->ab_addr  =   (sizeof(uint32) * CTC_FEATURE_MAX)*pp_num + pp_id*(CTC_WB_APPID_NUM *sizeof(ctc_wb_appid_t));
        g_wb_master[lchip]->ad_addr =   g_wb_master[CTC_MAP_LCHIP_BASE(lchip)]->ab_addr + CTC_WB_APPID_NUM *sizeof(ctc_wb_appid_t)*pp_num  ;
        g_wb_master[lchip]->actual_size = (sizeof(uint32) * CTC_FEATURE_MAX +  CTC_WB_APPID_NUM *sizeof(ctc_wb_appid_t))*pp_num;

       /* Get actual memory size under DM mode*/
       g_wb_master[lchip]->appid_hash = ctc_hash_create(CTC_WB_APPID_HASH_BlOCK_NUM,
                              CTC_WB_APPID_HASH_NUM / CTC_WB_APPID_HASH_BlOCK_NUM,
                                       (hash_key_fn) ctc_wb_dm_hash_make,
                                       (hash_cmp_fn) ctc_wb_dm_hash_cmp);

       if(!g_wb_master[lchip]->appid_hash)
        {
            return CTC_E_NO_MEMORY;
        }

      if(wb_api->reloading)
       {
          ret =ctc_wb_restore( lchip);
       }
    }
    else
    {
        g_wb_master[lchip]->init = wb_api->init;
        g_wb_master[lchip]->init_done = wb_api->init_done;
        g_wb_master[lchip]->sync = wb_api->sync;
        g_wb_master[lchip]->sync_done = wb_api->sync_done;
        g_wb_master[lchip]->add_entry = wb_api->add_entry;
        g_wb_master[lchip]->query_entry = wb_api->query_entry;
        ret = g_wb_master[lchip]->init(lchip, wb_api->reloading);
    }
    g_wb_master[lchip]->enable  = wb_api->enable;
    g_wb_master[lchip]->mode = wb_api->mode;


    if( wb_api->enable && wb_api->reloading && ret == CTC_E_NONE)
    { /*warmboot*/
        status = CTC_WB_STATUS_RELOADING;   /*reloading*/
    }
    else
    {
        status = CTC_WB_STATUS_DONE;  /*done*/
    }

    if(status == CTC_WB_STATUS_RELOADING && _ctc_wb_bmp_clear(lchip))
    {
        g_wb_master[lchip]->wb_status = CTC_WB_STATUS_RELOADING;
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Chip[%d] init with warmboot reloading.\n", lchip);
    }
    else
    {
        g_wb_master[lchip]->wb_status = CTC_WB_STATUS_DONE;
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Chip[%d] init with warmboot mode.\n", lchip);
        _ctc_wb_sync_bmp_init(lchip);
    }

    if (ret != CTC_E_NONE)
    {
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "ctc_wb_init error, ret = %d\n", ret);
    }

    return CTC_E_NONE;
 }



 int32 ctc_warmboot_init(uint8 ldev, ctc_wb_api_t *wb_api)
 {   
     uint8 pp_id = 0;
	 uint16 pp_base = CTC_MAP_LCHIP(ldev);
	 uint8 pp_num = CTC_MAP_LDEV_PP_NUM(ldev);
	 
     for (pp_id = 0; pp_id < pp_num; pp_id++)
     {
         ctc_wb_init(pp_base + pp_id, wb_api);

     }
	 return CTC_E_NONE;
 }

int32 ctc_wb_init_done(uint8 lchip)
{
    int32 ret = CTC_E_NONE;
    uint32 status = CTC_WB_STATUS_DONE;
	uint8 ldev = CTC_MAP_LDEV(lchip);

    lchip = g_ctcs_api_en ? lchip : 0;

    if (!CTC_WB_ENABLE(lchip))
    {
        return CTC_E_NONE;
    }

    if(g_wb_master[CTC_MAP_LCHIP_BASE(lchip)]->actual_size  >  g_wb_master[lchip]->total_size)
    {
        g_wb_master[lchip]->enable = 0;
        return CTC_E_NONE;
    }

    if (g_wb_master[lchip] && g_wb_master[lchip]->wb_status == CTC_WB_STATUS_RELOADING)
    {
        if(g_wb_master[lchip]->init_done)
        {
            ret = g_wb_master[lchip]->init_done(lchip);
            if (ret != CTC_E_NONE)
            {
                CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "ctc_wb_init_done error, ret = %d\n", ret);
                return CTC_E_INVALID_PARAM;
            }
        }

        if (g_ctcs_api_en)
        {
            CTC_ERROR_RETURN(ctcs_global_ctl_set(ldev, CTC_GLOBAL_WARMBOOT_STATUS, &status));
            for (lchip = 0; lchip < CTC_MAX_LOCAL_CHIP_NUM_PP; lchip++)
            {
                if(!g_wb_master[lchip])
                {
                    continue;
                }
                g_wb_master[lchip]->wb_status = status;/*done*/
            }
        }
        else
        {
            CTC_ERROR_RETURN(ctc_global_ctl_set(CTC_GLOBAL_WARMBOOT_STATUS, &status));
            for (lchip = 0; lchip < CTC_MAX_LOCAL_CHIP_NUM_PP; lchip++)
            {
               if(!g_wb_master[lchip])
               {
                   continue;
               }
                g_wb_master[lchip]->wb_status = status;/*done*/
            }
        }
    }

    return CTC_E_NONE;
}

int32 ctc_warmboot_init_done(uint8 ldev)
{
    uint8 pp_id = 0;
    uint16 pp_base = CTC_MAP_LCHIP(ldev);
    uint8 pp_num = CTC_MAP_LDEV_PP_NUM(ldev);
    
    for (pp_id = 0; pp_id < pp_num; pp_id++)
    {
        ctc_wb_init_done(pp_base + pp_id);
    }
    return CTC_E_NONE;
}

int32 ctc_wb_add_appid(uint8 lchip, ctc_wb_appid_t *app_id)
{
   ctc_wb_appid_t *new_node;
   int32 ret = CTC_E_NONE;
    if (!g_wb_master[lchip] ||
        !g_wb_master[lchip]->mode  ||
        !g_wb_master[lchip]->appid_hash )
    {
       return CTC_E_NONE;
    }
   if(app_id->entry_num == 0)
   {
       app_id->entry_num = 1;
       app_id->invalid  = 1;
   }
   else
   {
        app_id->invalid  = 0;
   }

   new_node = ctc_hash_lookup(g_wb_master[lchip]->appid_hash, app_id);
    g_wb_master[CTC_MAP_LCHIP_BASE(lchip)]->actual_size += (app_id->entry_num * app_id->entry_size);
    if(g_wb_master[CTC_MAP_LCHIP_BASE(lchip)]->actual_size  >  g_wb_master[lchip]->total_size  )
    {
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "warmboot [%s]not reserve enough memory\n",_ctc_wb_feature_desc(CTC_WB_MODID(app_id->app_id)));

       return CTC_E_NONE;
    }


    if(!new_node)
    {/*appid_header base address*/
       new_node = (ctc_wb_appid_t*) (g_wb_master[lchip]->start_addr +  g_wb_master[lchip]->ab_addr);

       new_node->addr_offset = g_wb_master[CTC_MAP_LCHIP_BASE(lchip)]->ad_addr;
       new_node->app_id = app_id->app_id;
       new_node->invalid =  app_id->invalid ;
       new_node->entry_num = app_id->entry_num;
       new_node->entry_size = app_id->entry_size;
       new_node->valid_cnt = 0;
       if(NULL == ctc_hash_insert(g_wb_master[lchip]->appid_hash, new_node))
       {
           return CTC_E_NO_MEMORY;
        }
       g_wb_master[lchip]->ab_addr += sizeof(ctc_wb_appid_t);
       g_wb_master[CTC_MAP_LCHIP_BASE(lchip)]->ad_addr += (app_id->entry_num * app_id->entry_size);
    }
    else
    {
      if(app_id->rt_en && (new_node->entry_size != app_id->entry_size))
       {
           CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Appid:%s%d old and new entry sizes are inonsistent and incompatible. \n",_ctc_wb_feature_desc(CTC_WB_MODID(app_id->app_id)),
           CTC_WB_SUBID(app_id->app_id));
           return CTC_E_NONE;
       }
        new_node->entry_size = app_id->entry_size;
        new_node->invalid =  app_id->invalid ;
    }
    if(app_id->rt_en ==1)
    {/*the appid support real-time syncup,and add index_app_id */
        ctc_wb_appid_t index_app_id,*p_appid;
        ctc_opf_t opf;
        sal_memset(&opf,0,sizeof(ctc_opf_t));
        index_app_id.app_id = ( (1<<31) |  app_id->app_id );
        index_app_id.entry_num = app_id->entry_num>>5;
		index_app_id.valid_cnt = 0;
        index_app_id.entry_size = 4; /*uint32*/
        index_app_id.rt_en = 0;
         p_appid = ctc_hash_lookup(g_wb_master[lchip]->appid_hash, &index_app_id);
         if(!p_appid  )
         {
            ret = ctc_opf_init2(&opf.pool_type , 1);
            ret = ret?:ctc_opf_init_offset(&opf, 0,app_id->entry_num);
            index_app_id.opf_type  = opf.pool_type;
            ret = ret?:ctc_wb_add_appid( lchip, &index_app_id);
            new_node->opf_type  = index_app_id.opf_type;
         }
         else
         {
           new_node->opf_type  = p_appid->opf_type;
         }
    }
    new_node->rt_en = app_id->rt_en;
   CTC_BIT_SET( g_wb_master[lchip]->appid_en[CTC_WB_MODID(app_id->app_id)],CTC_WB_SUBID(app_id->app_id));
   return ret;

}
uint8 ctc_wb_get_mode(uint8 lchip)
{
   if (!g_wb_master[lchip] || !g_wb_master[lchip]->enable)
   {
       return 0;
   }

   return g_wb_master[lchip]->mode;
}
uint8 ctc_wb_get_rt_en(uint8 lchip,uint8 mod_id,uint8 sub_id)
{
   ctc_wb_appid_t  lkup_node, *p_new_node;
   if (!CTC_WB_DM_MODE(lchip))
   {
       return 0;
   }
   lkup_node.app_id = (lchip <<16) | (mod_id<<8) |sub_id ;
   p_new_node = ctc_hash_lookup(g_wb_master[lchip]->appid_hash, &lkup_node);
   return  p_new_node ?p_new_node->rt_en:0 ;
}

int32
ctc_wb_restore(uint8 lchip)
{
   uint8 index= 0;
   ctc_wb_appid_t  *p_appid = NULL;
   uint32 *bitmap;
   uint16 loop =0,loop2=0;
   uint32 offset;
   uint32 valid_cnt = 0;
   ctc_opf_t opf;

   int32 ret = CTC_E_NONE;
   sal_memset(&opf,0,sizeof(ctc_opf_t));

   for(index = 0;index<CTC_WB_APPID_NUM;index++)
   {
       p_appid =(ctc_wb_appid_t*)(g_wb_master[lchip]->start_addr +  g_wb_master[lchip]->ab_addr);
       if(p_appid->entry_num ==0 && p_appid->app_id == 0)
       {
           break;
       }

       if(NULL == ctc_hash_insert(g_wb_master[lchip]->appid_hash, p_appid))
       {
           return CTC_E_NO_MEMORY;
       }
       g_wb_master[lchip]->ab_addr += sizeof(ctc_wb_appid_t);
       if(!CTC_WB_RT(p_appid->app_id)  )
       {
          continue;
       }
       /*restore index appid info.*/
       bitmap = (uint32*) ( g_wb_master[lchip]->start_addr +  p_appid->addr_offset);
       ret= ret ? : ctc_opf_init2(&opf.pool_type , 1);
       ret= ret ? : ctc_opf_init_offset(&opf, 0,(p_appid->entry_num<<5));
        p_appid->opf_type = opf.pool_type;
        do
        {
           if(valid_cnt == p_appid->valid_cnt)
           {
               break;
           }

           if(bitmap[loop] == 0)  continue;
           loop2 = 0;

           do
            {
             if(!CTC_IS_BIT_SET(bitmap[loop],loop2)) continue;

              valid_cnt++;
              offset = (loop<<5) + loop2;
              ret= ret ? : ctc_opf_alloc_offset_from_position(&opf, 1, offset);
            }while((++loop2)<32);
        }while((++loop) <p_appid->entry_num );
    }
     return ret;
}
void*
ctc_wb_malloc(uint8 lchip,  uint32 appid,uint32 type, uint32 size)
{

    ctc_wb_appid_t * p_master_appid,lkup_node;
    ctc_wb_appid_t * p_index_appid;
    ctc_opf_t opf;
    uint32 offset = 0;
    uint32 *bitmap;
	uint8   entry_num = 0;
	uint8   loop = 0;
    opf.pool_index = 0;
    opf.multiple = 0;
    opf.reverse = 0;
    
    if(!CTC_WB_DM_MODE(lchip))
    {
        return mem_malloc(type,size);
    }

    appid = lchip <<16 |  (appid & 0xFFFF);
    lkup_node.app_id = appid;
    p_master_appid = ctc_hash_lookup(g_wb_master[lchip]->appid_hash, &lkup_node);
    if (!p_master_appid ||  (p_master_appid->rt_en==0))
    {
        return NULL;
    }

    lkup_node.app_id = 1<<31 | appid;
    p_index_appid = ctc_hash_lookup(g_wb_master[lchip]->appid_hash, &lkup_node);
    if (!p_index_appid)
    {
      return NULL;
    }

    opf.pool_type = p_master_appid->opf_type;
	size = (size < p_master_appid->entry_size)?p_master_appid->entry_size:size;
	entry_num  = (size + p_master_appid->entry_size - 1)/p_master_appid->entry_size;

    if(ctc_opf_alloc_offset(&opf, entry_num, &offset)<0)
    {
       return NULL;
    }

    p_index_appid->valid_cnt += entry_num;
    bitmap = (uint32*) ( g_wb_master[lchip]->start_addr + p_index_appid->addr_offset);
	do{
       CTC_BIT_SET(bitmap[(offset+loop)>>5],(offset+loop)%32);
       loop++;
    }while(loop < entry_num );
   CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "ctc_wb_malloc(),index app id:0x%x,offset:%u set  bitmap[%d]:0x%x \n",appid, offset,offset>>5,bitmap[offset>>5]);

   return (void*)(g_wb_master[lchip]->start_addr+ p_master_appid->addr_offset + offset*p_master_appid->entry_size);

}

void
ctc_wb_free(uint8 lchip,uint32 appid, void* ptr,uint32 size)
{

    ctc_wb_appid_t * p_master_appid,lkup_node;
    ctc_wb_appid_t * p_index_appid;
    ctc_opf_t opf;
    uint32 offset = 0;
    uint32 *bitmap;
    uint8   loop = 0;
    uint8   entry_num = 0;

    if (!CTC_WB_DM_MODE(lchip))
    {
        mem_free(ptr);
        return;
    }

    opf.pool_index = 0;
    opf.multiple = 0;
    opf.reverse = 0;
    appid =lchip <<16 |  (appid & 0xFFFF);
    lkup_node.app_id = appid;
    p_master_appid = ctc_hash_lookup(g_wb_master[lchip]->appid_hash, &lkup_node);
    if (!p_master_appid ||  (p_master_appid->rt_en==0))
    {
        mem_free(ptr);
        return ;
    }

    if ((uintptr)ptr <(g_wb_master[lchip]->start_addr+ p_master_appid->addr_offset))
    {
     return ;
    }

    offset =  ((uintptr)ptr -g_wb_master[lchip]->start_addr- p_master_appid->addr_offset )/p_master_appid->entry_size;
    if(offset >= p_master_appid->entry_num)
    {
    return ;
    }

    size = (size < p_master_appid->entry_size)?p_master_appid->entry_size:size;
    entry_num  = (size + p_master_appid->entry_size - 1)/p_master_appid->entry_size;

    opf.pool_type = p_master_appid->opf_type;
    ctc_opf_free_offset(&opf, entry_num, offset);
    lkup_node.app_id = 1<<31 | appid;
    p_index_appid = ctc_hash_lookup(g_wb_master[lchip]->appid_hash, &lkup_node);
    if (!p_index_appid)
    {
     return ;
    }

    if(p_index_appid->valid_cnt)
    {
    	p_index_appid->valid_cnt -= entry_num;
    }
    bitmap = (uint32*) ( g_wb_master[lchip]->start_addr + p_index_appid->addr_offset);

    do{
    CTC_BIT_UNSET(bitmap[(offset+loop)>>5],(offset+loop)%32);
    loop++;
    }while(loop < entry_num );
    CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "ctc_wb_free(),index app id:0x%x,offset:%u unset  bitmap[%d]:0x%x \n",appid, offset,offset>>5,bitmap[offset>>5]);


}

uint32 ctc_wb_show_status(uint8 lchip)
{
    ctc_wb_appid_t * p_new_node, lkup_node;
     ctc_wb_appid_t * p_index_node;
    uint8 mod_id, sub_id, bit;
    uint32 total_actual_mem = 0;
    uint32 actual_mem;
    uint16 valid_cnt = 0;
    char app_desc[32] = {0};
    char mem_desc[32] = {0};

    if (!g_wb_master[lchip])
    {
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "warmboot is not enable!\n");
        return CTC_E_NONE;
    }

    CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s : %d\n","Warmboot Enable",g_wb_master[lchip]?g_wb_master[lchip]->enable:0);
    CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s : %s\n", "Work mode",g_wb_master[lchip]->mode?"DM":"DB");
    CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s : %u ms\n","TimeSync Interval", g_wb_master[lchip]->interval);
    CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s : %u KB\n","Reserved memory size", (g_wb_master[lchip]->total_size + CTC_CONST1024 - 1)>>10);
    CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-20s : %u KB\n", "Actual memory size",(g_wb_master[CTC_MAP_LCHIP_BASE(lchip)]->actual_size + CTC_CONST1024 - 1)>>10);

    if (!g_wb_master[lchip]->mode)
    {
       return CTC_E_NONE;
    }
    CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n------------------------------------------------------------------------------------------------------\n");
    CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"%-16s %-3s %-12s %-12s %-12s %-12s %-12s %-4s %-12s\n","app_id", "rt","entry_num", "entry_size","memory(B)", "valid_cnt", "used(%)","bmp", "addr_offset");
    CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "------------------------------------------------------------------------------------------------------\n");

    for (mod_id = 0; mod_id < CTC_FEATURE_MAX; mod_id++)
    {
        for (sub_id = 0; sub_id < CTC_WB_APPID_SUB_ID_NUM; sub_id++)
        {
            lkup_node.app_id = lchip << 16 | CTC_WB_APPID(mod_id, sub_id);
            p_new_node = ctc_hash_lookup(g_wb_master[lchip]->appid_hash, &lkup_node);
            if (!p_new_node)
            {
                CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_INFO,"%-8X find hash node error!\n",lkup_node.app_id);
                continue;
            }
            if(p_new_node->rt_en)
            {
                lkup_node.app_id = 1<<31 | lchip << 16 | CTC_WB_APPID(mod_id, sub_id);
                p_index_node = ctc_hash_lookup(g_wb_master[lchip]->appid_hash, &lkup_node);
               if(p_index_node)    p_new_node->valid_cnt = p_index_node->valid_cnt;
            }
            actual_mem = p_new_node->entry_num * p_new_node->entry_size;
            total_actual_mem += actual_mem;

            sal_sprintf(app_desc,"%s_%d",_ctc_wb_feature_desc(mod_id),sub_id);
            sal_sprintf(mem_desc,"%d%s",((actual_mem >1024) ?(actual_mem >>10):actual_mem),((actual_mem >1024) ?"K":""));
            bit = CTC_WB_DM_MODE(lchip)?CTC_IS_BIT_SET(g_wb_master[lchip]->sync_bmp[mod_id], sub_id):0;
            CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"%-16s %-3d %-12u %-12u %-12s %-12u %-12u %-4u 0x%-.8x\n",app_desc ,p_new_node->rt_en?1:0,p_new_node->invalid?0:p_new_node->entry_num,p_new_node->entry_size, mem_desc, p_new_node->valid_cnt,p_new_node->valid_cnt?( p_new_node->valid_cnt*100/p_new_node->entry_num):0, bit, p_new_node->addr_offset);
            valid_cnt++;
        }
    }
    CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n------------------------------------------------------------------------------------------------------\n");
    CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Valid Cnt :%d\n",valid_cnt);

    return CTC_E_NONE;

}


int32 ctc_wb_sync(uint8 lchip)
{
    int32 ret = CTC_E_NONE;
    uint32 status = CTC_WB_STATUS_SYNC;
	uint8 ldev = CTC_MAP_LDEV(lchip);
    sal_systime_t tv1,tv2;
    sal_gettime(&tv1);

    lchip = g_ctcs_api_en ? lchip : 0;

    if (!CTC_WB_ENABLE(lchip))
    {
        return CTC_E_NOT_READY;
    }

    if (!g_wb_master[lchip]->mode)
    {
        ret = g_wb_master[lchip]->sync(lchip);
        if (ret != CTC_E_NONE)
        {
            CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "ctc_wb_sync error, ret = %d\n", ret);
            return CTC_E_INVALID_PARAM;
        }
    }

    if (g_ctcs_api_en)
    {
        CTC_ERROR_RETURN(ctcs_global_ctl_set(ldev, CTC_GLOBAL_WARMBOOT_STATUS, &status));
        g_wb_master[lchip]->wb_status = g_wb_master[lchip]->mode ?CTC_WB_STATUS_DONE: CTC_WB_STATUS_SYNC;/*sync*/
    }
    else
    {
        CTC_ERROR_RETURN(ctc_global_ctl_set(CTC_GLOBAL_WARMBOOT_STATUS, &status));
         for (lchip = 0; lchip < CTC_MAX_LOCAL_CHIP_NUM_PP; lchip++)
         {
               if(!g_wb_master[lchip])
               {
                   continue;
               }
               g_wb_master[lchip]->wb_status = g_wb_master[lchip]->mode ?CTC_WB_STATUS_DONE: CTC_WB_STATUS_SYNC;/*sync*/
          }
    }
    sal_gettime(&tv2);
    if(tv2.tv_usec >= tv1.tv_usec)
    {
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_PARAM,"USED  TIME:[%10u s:%3u ms]\n", tv2.tv_sec - tv1.tv_sec, (tv2.tv_usec - tv1.tv_usec)/1000);
    }
    else
    {
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_PARAM,"USED  TIME:[%10u s:%3u ms]\n", tv2.tv_sec - tv1.tv_sec - 1, (tv2.tv_usec + 1000000 - tv1.tv_usec)/1000);
    }
    return CTC_E_NONE;
}

int32 ctc_wb_sync_done(uint8 lchip, int32 result)
{
    int32 ret = CTC_E_NONE;
    uint32 status = CTC_WB_STATUS_DONE;
	uint8 ldev = CTC_MAP_LDEV(lchip);
    sal_systime_t tv1,tv2;
    sal_gettime(&tv1);
    lchip = g_ctcs_api_en ? lchip : 0;

    if (!CTC_WB_ENABLE(lchip))
    {
        return CTC_E_NOT_READY;
    }

     if (!g_wb_master[lchip]->mode)
    {
        ret = g_wb_master[lchip]->sync_done(lchip, result);
        if (ret != CTC_E_NONE)
        {
            CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "ctc_wb_sync_done error\n");
        }
    }
    else
    {
       ctc_pmem_sync (lchip,g_wb_master[lchip]->start_addr , g_wb_master[lchip]->total_size);
    }

    if (g_ctcs_api_en)
    {
        g_wb_master[lchip]->wb_status = status;/*done*/
        CTC_ERROR_RETURN(ctcs_global_ctl_set(ldev, CTC_GLOBAL_WARMBOOT_STATUS, &status));
    }
    else
    {
       for (lchip = 0; lchip < CTC_MAX_LOCAL_CHIP_NUM_PP; lchip++)
        {
              if(!g_wb_master[lchip])
              {
                   continue;
              }
              g_wb_master[lchip]->wb_status = status;/*done*/
        }
        CTC_ERROR_RETURN(ctc_global_ctl_set(CTC_GLOBAL_WARMBOOT_STATUS, &status));

    }
    sal_gettime(&tv2);
    if(tv2.tv_usec >= tv1.tv_usec)
    {
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_PARAM,"USED  TIME:[%10u s:%3u ms]\n", tv2.tv_sec - tv1.tv_sec, (tv2.tv_usec - tv1.tv_usec)/1000);
    }
    else
    {
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_PARAM,"USED  TIME:[%10u s:%3u ms]\n", tv2.tv_sec - tv1.tv_sec - 1, (tv2.tv_usec + 1000000 - tv1.tv_usec)/1000);
    }
    return ret;
}

int32 ctc_wb_add_entry(ctc_wb_data_t *data)
{
   int32 ret = CTC_E_NONE;
   ctc_wb_appid_t  lkup_node, *p_new_node;
   uint8 lchip = CTC_WB_CHIPID(data->app_id);

    if (!CTC_WB_ENABLE(lchip))
    {
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "warmboot is not enable!\n");
        return CTC_E_NOT_READY;
    }

    CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Add %4d entry to appid: %s%d  table on chip %u\n",
        data->valid_cnt, _ctc_wb_feature_desc(CTC_WB_MODID(data->app_id)), CTC_WB_SUBID(data->app_id), CTC_WB_CHIPID(data->app_id));

    if (g_wb_master[lchip]->mode)
    {

        uintptr mem_addr;
        lkup_node.app_id = data->app_id;
        p_new_node = ctc_hash_lookup(g_wb_master[lchip]->appid_hash, &lkup_node);
        if (p_new_node == NULL)
        {
            return CTC_E_INVALID_PARAM;
        }

        if ((p_new_node->valid_cnt + data->valid_cnt) > p_new_node->entry_num)
        {
            CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Memory overlap !! appid:0x%x, validCnt %4u > maxNum %4u\n",
                           data->app_id,(p_new_node->valid_cnt + data->valid_cnt), p_new_node->entry_num);
           return CTC_E_NO_MEMORY;
        }
        mem_addr = g_wb_master[lchip]->start_addr + p_new_node->addr_offset;
        p_new_node->valid_cnt += data->valid_cnt;
        ctc_pmem_sync (CTC_MAP_LDEV(CTC_WB_CHIPID(data->app_id)),mem_addr , data->valid_cnt *p_new_node->entry_size);

    }
    else
    {
        ret = g_wb_master[lchip]->add_entry ? g_wb_master[lchip]->add_entry(data) : CTC_E_NOT_SUPPORT;
        if (ret != CTC_E_NONE && ret != CTC_E_NOT_SUPPORT)
        {
            CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "ctc_wb_add_entry error\n");
            ret = CTC_E_INVALID_PARAM;
        }
    }

    return ret;
}

int32 ctc_wb_query_entry(ctc_wb_query_t *query)
{
    int32 ret = CTC_E_NONE;
    uint8 lchip = 0;

    lchip = CTC_WB_CHIPID(query->app_id);
    if (!CTC_WB_ENABLE(lchip))
    {
        return CTC_E_NONE;
    }

    if (g_wb_master[lchip]->mode)
    {
        ctc_wb_appid_t  lkup_node, *p_new_node;
        lkup_node.app_id = query->app_id;

        p_new_node = ctc_hash_lookup(g_wb_master[lchip]->appid_hash, &lkup_node);
        if (!p_new_node)
        {
            /*CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Query app_id: %d no exist\n", query->app_id);*/
            query->valid_cnt = 0;
            query->is_end = 1;
            return CTC_E_NONE;
        }
        query->buffer =  (ctc_wb_key_data_t*)( g_wb_master[lchip]->start_addr + p_new_node->addr_offset);
        if(p_new_node->rt_en)
        {
              ctc_wb_appid_t * p_index_appid;
              lkup_node.app_id =  1<<31 | query->app_id ;

              p_index_appid = ctc_hash_lookup(g_wb_master[lchip]->appid_hash, &lkup_node);
              if(p_index_appid)
              {
                    query->ext_data =  (void*)( g_wb_master[lchip]->start_addr + p_index_appid->addr_offset);
                    query->valid_cnt = p_index_appid->valid_cnt;
              }
              else
              {
                  query->valid_cnt = 0;
              }
              query->buffer_len = p_new_node->entry_size * p_new_node->entry_num;

        }
        else
        {
            query->buffer_len = p_new_node->entry_size * p_new_node->valid_cnt;
            query->valid_cnt = p_new_node->valid_cnt;
        }
        query->key_len = 0;
        query->data_len = p_new_node->entry_size;
        query->is_end = 1;
    }
    else
    {
        ret = g_wb_master[lchip]->query_entry ? g_wb_master[lchip]->query_entry(query) : CTC_E_NOT_SUPPORT;
    }
    CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Query mod_id: %2d sub_id:%2d (appid: %4d) table on chip %u, entry count: %4d, cursor: %6d, end: %d\n",
            CTC_WB_MODID(query->app_id), CTC_WB_SUBID(query->app_id), query->app_id,
            CTC_WB_CHIPID(query->app_id), query->valid_cnt, query->cursor, query->is_end);

    if (ret != CTC_E_NONE && ret != CTC_E_NOT_SUPPORT)
    {
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "ctc_wb_query_entry error, ret\n");
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Query app_id: %d no exist\n", query->app_id);
        ret = CTC_E_INVALID_PARAM;
    }

    return ret;
}

int32 ctc_wb_set_cpu_rx_en(uint8 lchip, bool enable)
{
    bool value = FALSE;
	uint8 ldev = CTC_MAP_LDEV(lchip);

    if (!CTC_WB_ENABLE(lchip))
    {
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "warmboot is not enable!\n");
        return CTC_E_NOT_READY;
    }

    value = enable;
    if (g_ctcs_api_en)
    {
        CTC_ERROR_RETURN(ctcs_global_ctl_set(ldev, CTC_GLOBAL_WARMBOOT_CPU_RX_EN, &value));
    }
    else
    {
        CTC_ERROR_RETURN(ctc_global_ctl_set(CTC_GLOBAL_WARMBOOT_CPU_RX_EN, &value));
    }

    return CTC_E_NONE;
}

int32 ctc_wb_get_cpu_rx_en(uint8 lchip, bool* enable)
{
    uint32 value = FALSE;
	uint8 ldev = CTC_MAP_LDEV(lchip);
    CTC_PTR_VALID_CHECK(enable);

    if (!CTC_WB_ENABLE(lchip))
    {
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "warmboot is not enable!\n");
        return CTC_E_NOT_READY;
    }

    if (g_ctcs_api_en)
    {
        CTC_ERROR_RETURN(ctcs_global_ctl_get(ldev, CTC_GLOBAL_WARMBOOT_CPU_RX_EN, &value));
    }
    else
    {
        CTC_ERROR_RETURN(ctc_global_ctl_get(CTC_GLOBAL_WARMBOOT_CPU_RX_EN, &value));
    }
    *enable = value ? TRUE : FALSE;

    return CTC_E_NONE;
}

int32
ctc_wb_set_interval(uint8 lchip, uint32 interval)
{
	uint8 ldev = CTC_MAP_LDEV(lchip);

    if (!CTC_WB_ENABLE(lchip) || !CTC_WB_DM_MODE(lchip))
    {
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "warmboot is not enable!\n");
        return CTC_E_NOT_READY;
    }

    if (g_ctcs_api_en)
    {
        CTC_ERROR_RETURN(ctcs_global_ctl_set(ldev, CTC_GLOBAL_WARMBOOT_INTERVAL, &interval));
    }
    else
    {
        CTC_ERROR_RETURN(ctc_global_ctl_set(CTC_GLOBAL_WARMBOOT_INTERVAL, &interval));
    }
    g_wb_master[lchip]->interval = interval;
    return CTC_E_NONE;
}

int32
ctc_wb_get_interval(uint8 lchip, uint32* interval)
{
	uint8 ldev = CTC_MAP_LDEV(lchip);

    CTC_PTR_VALID_CHECK(interval);

    if (!CTC_WB_ENABLE(lchip))
    {
        CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "warmboot is not enable!\n");
        return CTC_E_NOT_READY;
    }

    if (g_ctcs_api_en)
    {
        CTC_ERROR_RETURN(ctcs_global_ctl_get(ldev, CTC_GLOBAL_WARMBOOT_INTERVAL, interval));
    }
    else
    {
        CTC_ERROR_RETURN(ctc_global_ctl_get(CTC_GLOBAL_WARMBOOT_INTERVAL, interval));
    }

    return CTC_E_NONE;
}

int32 ctc_wb_deinit(uint8 lchip)
{
  if (!g_wb_master[lchip])
   {
        return CTC_E_NONE;
   }
   g_wb_master[lchip]->wb_status = 0;
   ctc_hash_free(g_wb_master[lchip]->appid_hash);
   mem_free(g_wb_master[lchip]);
   g_wb_master[lchip] = NULL;

    return CTC_E_NONE;
}

int32 ctc_warmboot_deinit(uint8 ldev)
{	
	uint8 pp_id = 0;
	uint16 pp_base = CTC_MAP_LCHIP(ldev);
	uint8 pp_num = CTC_MAP_LDEV_PP_NUM(ldev);
	
	for (pp_id = 0; pp_id < pp_num; pp_id++)
	{
		ctc_wb_deinit(pp_base + pp_id);

	}
	return CTC_E_NONE;
}

